package com.smart.service.oss;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.smart.common.entities.constant.SmartConstant;
import com.smart.common.entities.file.UploadBody;
import com.smart.common.entities.file.UploadResult;
import com.smart.common.exception.SmartException;
import com.smart.manager.system.repository.ConfigRepository;
import com.smart.utils.ContentTypeUtil;
import com.smart.utils.FileUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Set;

/**
 * 阿里云文件处理程序
 *
 * @author Administrator
 * @date 2022/09/09
 */

@Component
@RequiredArgsConstructor
@Log4j2
public class AliYunFileHandler {

    private final ConfigRepository configRepository;


    /**
     * 读取配置
     *
     * @return {@code ConfigAssembler.OssBase}
     */
    private JSONObject readConfig() {
        JSONObject jsonObject = configRepository.readCache(SmartConstant.ALIYUN_OSS_CFG);
        Set<String> mustKeys = Set.of("accessKey", "secretKey", "bucket", "readPath", "endpoint");
        Assert.isTrue(jsonObject.keySet().containsAll(mustKeys), "阿里云OSS 参数配置必须包含以下参数字段:" + mustKeys);
        Assert.isTrue(ObjectUtil.isAllNotEmpty(jsonObject), "阿里云OSS  参数配置存在空配置字段");
        return jsonObject;
    }

    /**
     * 获取阿里云上传客户端
     *
     * @param config 配置
     * @return {@code OSS}
     */
    private OSS getOssClient(JSONObject config) {

        return new OSSClientBuilder().build(config.getString("endpoint"), config.getString("accessKey")
                , config.getString("secretKey"));
    }
    /**
     * 得到上传结果
     * @param newFileName 新文件名字
     * @param config      配置
     * @return {@link UploadResult}
     */
    private UploadResult getUploadResult(String newFileName, JSONObject config) {
        String url = config.getString("readPath").concat("/").concat(newFileName);
        return new UploadResult().setUid(StrUtil.uuid()).setName(newFileName).setUrl(url);
    }
    /**
     * 得到上传结果
     * @param newFileName 新文件名字
     * @param config      配置
     * @param fileName    原文件名称
     * @return {@link UploadResult}
     */
    private UploadResult getUploadResult(String newFileName, JSONObject config,String fileName) {
        String url = config.getString("readPath").concat("/").concat(newFileName);
        return new UploadResult().setUid(StrUtil.uuid()).setName(fileName).setUrl(url);
    }

    /**
     * 阿里云上传文件处理器
     *
     * @param file           文件
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadImg(MultipartFile file, String topFolder, String fileNamePrefix) {
        try {
            Assert.notNull(file, "上传文件不能为空");
            String filename = file.getOriginalFilename();
            String ext = filename.substring(filename.indexOf("."));
            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            JSONObject config = this.readConfig();
            OSS ossClient = getOssClient(config);
            ossClient.putObject(config.getString("bucket"), newFileName, file.getInputStream());
            ossClient.shutdown();
            return getUploadResult(newFileName, config,filename);
        } catch (IOException e) {
            throw new SmartException("文件读取异常:" + e.getMessage());
        }
    }


    /**
     * 阿里云文件对象上传
     *
     * @param file           文件
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(MultipartFile file, String topFolder, String fileNamePrefix) {
        try {
            Assert.notNull(file, "上传文件不能为空");
            String filename = file.getOriginalFilename();
            String ext = filename.substring(filename.indexOf("."));
            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            JSONObject config = this.readConfig();
            OSS ossClient = getOssClient(config);
            ossClient.putObject(config.getString("bucket"), newFileName, file.getInputStream());
            ossClient.shutdown();
            return getUploadResult(newFileName, config,filename);
        } catch (Exception e) {
            throw new SmartException("文件读取异常:" + e.getMessage());
        }
    }


    /**
     * 阿里云 Base64上传文件
     *
     * @param dto            dto
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(UploadBody.Base64 dto, String topFolder, String fileNamePrefix,Boolean isImg) {
        try {
            //解析BASE64字符串内的文件类型
            String contentType = dto.getBase64().substring(0, dto.getBase64().indexOf(",")).replace("data:", "").replace(";base64", "");
            String s = ContentTypeUtil.getExt(contentType);
            String ext = StrUtil.isNotBlank(s) ? s : ".data";
            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            byte[] uploadBytes = FileUtils.base64StringToByte(dto.getBase64());
            JSONObject config = this.readConfig();
            OSS ossClient = getOssClient(config);
            String bucket = config.getString("bucket");
            //如果是图片
            if (isImg) {
                ObjectMetadata meta = new ObjectMetadata();
                meta.setContentType("image/jpg");
                ossClient.putObject(bucket, newFileName, new ByteArrayInputStream(uploadBytes),meta);
            }else {
                ossClient.putObject(bucket, newFileName, new ByteArrayInputStream(uploadBytes));
            }
            ossClient.putObject(bucket, newFileName, new ByteArrayInputStream(uploadBytes));
            ossClient.shutdown();
            return getUploadResult(newFileName, config);
        } catch (Exception e) {
            throw new SmartException("文件上传失败:" + e.getMessage());
        }


    }


    /**
     * 阿里云 Byte上传文件
     *
     * @param dto            dto
     * @param topFolder      顶级文件夹
     * @param fileNamePrefix 文件名前缀
     * @return {@code UploadResult}
     */
    public UploadResult uploadFile(UploadBody.ByteFile dto, String topFolder, String fileNamePrefix) {

        try {
            String s = ContentTypeUtil.getExt(dto.getContentType());
            String ext = StrUtil.isBlank(s) ? ".xlsx" : s;
            String newFileName = FileUtils.getFileName(topFolder, ext, fileNamePrefix);
            JSONObject config = this.readConfig();
            OSS ossClient = getOssClient(config);
            String bucket = config.getString("bucket");
            ossClient.putObject(bucket, newFileName, new ByteArrayInputStream(dto.getData()));
            ossClient.shutdown();
            return getUploadResult(newFileName, config);
        } catch (Exception e) {
            throw new SmartException("文件上传失败:" + e.getMessage());
        }
    }


    public UploadResult uploadMp4File(UploadBody.ByteFile dto, String topFolder, String fileNamePrefix) {

        try {
            String s = ContentTypeUtil.getExt(dto.getContentType());
            String newFileName = FileUtils.getFileName(topFolder, ".mp4", fileNamePrefix);
            JSONObject config = this.readConfig();
            OSS ossClient = getOssClient(config);
            String bucket = config.getString("bucket");
            ossClient.putObject(bucket, newFileName, new ByteArrayInputStream(dto.getData()));
            ossClient.shutdown();
            return getUploadResult(newFileName, config);
        } catch (Exception e) {
            throw new SmartException("文件上传失败:" + e.getMessage());
        }
    }
}
